import sys # 确保这行存在
from concurrent.futures import ThreadPoolExecutor

import cv2
import numpy as np
import pyautogui
import win32gui
import win32con
import win32api
import time
import os
from pynput.keyboard import Controller, Key
import logging

# === 常量定义 ===
try:
    TEMPLATE_DIR = os.path.join(os.path.dirname(__file__), "templates")
except NameError:
    TEMPLATE_DIR = os.path.join(os.getcwd(), "templates")

# 模板名到按键的映射
SKILL_KEY_MAP = {
    "gold_qianghua_skill1.png": "u",
    "gold_qianghua_skill2.png": "i",
    "gold_skill4.png": "r",
    "skill1.png": "u",
    "skill2.png": "i",
    "skill3.png": "o",
    "qianghua_skill1.png": "u",
    "qianghua_skill2.png": "i",
    "qianghua_skill3.png": "o"
}


# === 基础功能函数 ===

# !!! 确保这一行在所有调用 keyboard 之前，且没有缩进 !!!
keyboard = Controller()

# ... template_path, find_window 等辅助函数 ...

# !!! 确保 press_key 函数的定义也在这里，没有缩进，在任何函数之外 !!!
def press_key(key_to_press, key_name=""):
    """
    使用 pynput 模拟按下并释放指定按键。
    参数：
        key_to_press: pynput.keyboard.Key 对象（如 Key.enter）或字符串（如 'j'）。
        key_name (str): 用于日志输出的按键名称。
    """
    keyboard.press(key_to_press)
    time.sleep(0.05) # 短暂延迟确保按键注册
    keyboard.release(key_to_press)
    if key_name:
        logging.info(f"已按下 {key_name} 键。")

def press_key_by_name(key_name):
    """模拟按下并释放指定的按键。"""
    try:
        vk_code = win32api.VkKeyScan(key_name)
        if vk_code == -1:
            if len(key_name) == 1 and 'A' <= key_name.upper() <= 'Z':
                vk_code = ord(key_name.upper())
            else:
                print(f"无法识别按键：{key_name}")
                return

        actual_vk_code = vk_code & 0xFF

        win32api.keybd_event(actual_vk_code, 0, 0, 0)
        time.sleep(0.05)
        win32api.keybd_event(actual_vk_code, 0, win32con.KEYEVENTF_KEYUP, 0)
        print(f"已按下技能键 ({key_name})")
    except Exception as e:
        print(f"按下按键 {key_name} 时发生错误: {e}")


def press_key_for_template(template_name):
    """根据模板图片名称查找并按下对应的技能键。"""
    key = SKILL_KEY_MAP.get(template_name)
    if key:
        press_key_by_name(key)
    else:
        print(f"未找到模板 {template_name} 对应的按键。")


def template_path(filename):
    """获取模板图片的完整路径。"""
    return os.path.join(TEMPLATE_DIR, filename)


def screenshot_window(hwnd):
    """截取指定窗口的图像。"""
    if not win32gui.IsWindow(hwnd):
        print(f"错误：窗口句柄 {hwnd} 无效。")
        return None, (0, 0)
    try:
        left, top, right, bottom = win32gui.GetWindowRect(hwnd)
        if right <= left or bottom <= top:
            print(f"错误：窗口 {hwnd} 尺寸无效 ({left},{top},{right},{bottom})。可能已最小化或关闭。")
            if win32gui.IsIconic(hwnd):
                win32gui.ShowWindow(hwnd, win32con.SW_RESTORE)
                time.sleep(0.5)
                left, top, right, bottom = win32gui.GetWindowRect(hwnd)
            if right <= left or bottom <= top:
                return None, (0, 0)

        width, height = right - left, bottom - top
        screenshot = pyautogui.screenshot(region=(left, top, width, height))
        return cv2.cvtColor(np.array(screenshot), cv2.COLOR_RGB2BGR), (left, top)
    except Exception as e:
        print(f"截取窗口 {hwnd} 图像时发生错误: {e}")
        return None, (0, 0)


def match_template(img, template_path_str, threshold=0.8):
    """在图像中匹配单个模板。"""
    if img is None:
        print("错误：用于模板匹配的输入图像为空。")
        return None, 0, 0
    template = cv2.imread(template_path_str, cv2.IMREAD_COLOR)
    if template is None:
        print(f"模板读取失败：{template_path_str}。请检查路径和文件是否存在。")
        return None, 0, 0
    if template.shape[0] > img.shape[0] or template.shape[1] > img.shape[1]:
        print(
            f"错误：模板 {template_path_str} (尺寸: {template.shape[1]}x{template.shape[0]}) 大于图像 (尺寸: {img.shape[1]}x{img.shape[0]})。")
        return None, 0, 0
    try:
        result = cv2.matchTemplate(img, template, cv2.TM_CCOEFF_NORMED)
        _, max_val, _, max_loc = cv2.minMaxLoc(result)
        if max_val >= threshold:
            return max_loc, template.shape[1], template.shape[0]
    except cv2.error as e:
        print(f"OpenCV 模板匹配错误 ({template_path_str}): {e}")
        print(f"图像尺寸: {img.shape}, 模板尺寸: {template.shape}")
    return None, 0, 0


def match_template_threaded(img, template_list, offset, threshold=0.8, max_workers=4):
    """并行匹配多个模板图片，返回最先匹配成功的模板名及中心坐标。"""
    if img is None:
        print("错误：用于多模板匹配的输入图像为空。")
        return None

    def task(template_name):
        path = template_path(template_name)
        match_pos, w, h = match_template(img, path, threshold)
        if match_pos:
            return {
                "template": template_name,
                "pos": (offset[0] + match_pos[0] + w // 2, offset[1] + match_pos[1] + h // 2)
            }
        return None

    with ThreadPoolExecutor(max_workers=max_workers) as executor:
        futures = [executor.submit(task, t) for t in template_list]
        for future in futures:
            result = future.result()
            if result:
                return result
    return None


def click_at(x, y):
    """移动鼠标到指定坐标并单击。"""
    pyautogui.moveTo(x, y)
    pyautogui.click()


def press_j_once():
    """按下并释放J键一次。"""
    win32api.keybd_event(0x4A, 0, 0, 0)
    time.sleep(0.05)
    win32api.keybd_event(0x4A, 0, win32con.KEYEVENTF_KEYUP, 0)


def press_j_combo(count=5, interval=0.3):
    """执行J键普攻连击。"""
    print(f"执行普攻连击 (J x {count})")
    for _ in range(count):
        press_j_once()
        time.sleep(interval)


def press_space():
    """按下并释放空格键。"""
    win32api.keybd_event(win32con.VK_SPACE, 0, 0, 0)
    time.sleep(0.05)
    win32api.keybd_event(win32con.VK_SPACE, 0, win32con.KEYEVENTF_KEYUP, 0)
    print("已按下闪避键 (Space)")


# === 主要游戏逻辑函数 ===
def handle_gameplay_actions(hwnd, skill_templates_gold, skill_templates_white,
                            red_flash_threshold=150, match_threshold=0.8, loop_duration=60):
    """
    处理核心的游戏内动作循环。
    """
    print(f"开始执行游戏内动作循环，句柄: {hwnd}，持续约 {loop_duration} 秒...")
    start_time = time.time()
    end_time = start_time + loop_duration
    last_dodge_time = 0
    dodge_cooldown = 1.0
    consecutive_gold_skill_count = 0

    while time.time() < end_time:
        screen_img_bgr, offset = screenshot_window(hwnd)
        if screen_img_bgr is None:
            print("无法获取屏幕截图，可能窗口已关闭或最小化。正在尝试跳过此帧...")
            time.sleep(0.5)
            continue

        screen_img_rgb = cv2.cvtColor(screen_img_bgr, cv2.COLOR_BGR2RGB)
        avg_red = np.mean(screen_img_rgb[:, :, 0])
        current_time = time.time()

        # 1. 闪避逻辑
        if avg_red > red_flash_threshold and (current_time - last_dodge_time > dodge_cooldown):
            press_space()
            last_dodge_time = current_time
            consecutive_gold_skill_count = 0
            time.sleep(0.3)
            continue

        skill_used_this_iteration = False
        is_gold_skill_clicked_this_turn = False

        # 2. 金色技能逻辑
        gold_match = match_template_threaded(screen_img_bgr, skill_templates_gold, offset, match_threshold)
        if gold_match:
            press_key_for_template(gold_match["template"])
            print(f"已释放金色技能: {gold_match['template']}")
            skill_used_this_iteration = True
            is_gold_skill_clicked_this_turn = True
            consecutive_gold_skill_count += 1
            time.sleep(0.2)
        else:
            # 3. 白色技能逻辑 (仅当没有金色技能匹配时)
            white_match = match_template_threaded(screen_img_bgr, skill_templates_white, offset, match_threshold)
            if white_match:
                press_key_for_template(white_match["template"])
                print(f"已释放白色技能: {white_match['template']}")
                skill_used_this_iteration = True
                consecutive_gold_skill_count = 0
                time.sleep(0.2)

        # 4. 普攻逻辑
        if skill_used_this_iteration:
            if is_gold_skill_clicked_this_turn and consecutive_gold_skill_count >= 2:
                press_j_combo(5, 0.3)
                consecutive_gold_skill_count = 0
        else:
            press_j_once()
            consecutive_gold_skill_count = 0
            time.sleep(0.001)

    print("游戏内动作循环执行完毕。")


# === 窗口查找函数 ===
def find_window(title_part="AetherGazer"):
    """
    查找包含指定标题部分的可见窗口。
    """
    top_windows = []
    win32gui.EnumWindows(
        lambda hwnd, 结果: 结果.append(hwnd) if win32gui.IsWindowVisible(hwnd) and title_part in win32gui.GetWindowText(
            hwnd) else None, top_windows)
    return top_windows[0] if top_windows else None


# === 主要执行函数 (封装后的入口) ===
def run_game_automation(window_title="AetherGazer",
                        gold_skills_config=None,
                        white_skills_config=None,
                        duration=85,
                        flash_threshold=150,
                        match_conf=0.8):
    """
    游戏自动化主控制函数。
    负责查找窗口、配置参数并启动核心的游戏动作循环。
    """
    print(f"正在尝试查找窗口: '{window_title}'...")
    hwnd = find_window(window_title)

    if not hwnd:
        print(f"错误：未找到游戏窗口。请确认游戏正在运行且窗口标题包含 '{window_title}'。")
        print(f"提示：请确保 {TEMPLATE_DIR} 目录存在且包含所需的 .png 模板图片。")
        return

    print(f"成功找到窗口 '{win32gui.GetWindowText(hwnd)}' (句柄: {hwnd})。")

    if gold_skills_config is None:
        gold_skills_to_use = ["gold_qianghua_skill1.png", "gold_qianghua_skill2.png", "gold_skill4.png"]
    else:
        gold_skills_to_use = gold_skills_config

    if white_skills_config is None:
        white_skills_to_use = ["skill1.png", "skill2.png", "skill3.png", "qianghua_skill1.png", "qianghua_skill2.png",
                               "qianghua_skill3.png"]
    else:
        white_skills_to_use = white_skills_config

    if not os.path.isdir(TEMPLATE_DIR):
        print(f"错误：模板目录 '{TEMPLATE_DIR}' 不存在。请创建该目录并将模板图片放入其中。")
        return

    all_skills = gold_skills_to_use + white_skills_to_use
    missing_templates = [skill for skill in all_skills if not os.path.exists(template_path(skill))]
    if missing_templates:
        print(f"错误：以下模板文件在 '{TEMPLATE_DIR}' 目录中缺失：")
        for mt in missing_templates:
            print(f"- {mt}")
        return

    print(f"自动化配置：")
    print(f"  - 持续时间: {duration} 秒")
    print(f"  - 红色闪烁阈值: {flash_threshold}")
    print(f"  - 模板匹配阈值: {match_conf}")
    print(f"  - 金色技能模板: {gold_skills_to_use}")
    print(f"  - 白色技能模板: {white_skills_to_use}")

    try:
        handle_gameplay_actions(hwnd,
                                gold_skills_to_use,
                                white_skills_to_use,
                                red_flash_threshold=flash_threshold,
                                match_threshold=match_conf,
                                loop_duration=duration)
    except Exception as e:
        print(f"在执行游戏自动化过程中发生严重错误: {e}")
    finally:
        print("自动化流程结束。")
        press_key(Key.enter, 'Enter')  # 流程结束后再次按下 Enter 键
        print("等待5秒后尝试点击 home.png 图像...")
        time.sleep(4)  # 等待4秒

        # 重新获取游戏窗口截图
        screen_img_bgr, offset = screenshot_window(hwnd)

        if screen_img_bgr is not None:
            home_template_path = template_path("home.png")
            if os.path.exists(home_template_path):
                match_result = match_template(screen_img_bgr, home_template_path, match_conf)
                if match_result[0] is not None:
                    match_pos, w, h = match_result
                    # 计算 home.png 的中心坐标
                    center_x = offset[0] + match_pos[0] + w // 2
                    center_y = offset[1] + match_pos[1] + h // 2
                    click_at(center_x, center_y)
                    print(f"已在游戏窗口内点击 home.png 图像的中心位置 ({center_x}, {center_y})。")
                else:
                    print("未找到 home.png 图像。")
            else:
                print(f"错误： home.png 模板文件在 '{TEMPLATE_DIR}' 目录中不存在。")
        else:
            print("无法获取游戏窗口截图，跳过点击 home.png。")


# === 当脚本被直接执行时 ===
if __name__ == "__main__":
    print("脚本作为主程序运行...")
    run_game_automation(
        window_title="AetherGazer",
        duration=80,
        match_conf=0.75
    )